package com.ocom.human.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ocom.common.entity.aiot.EntityMjAppVerInfo;
import com.ocom.common.entity.human.EntityPersonnelFeature;
import com.ocom.common.enums.DataSourceEnum;
import com.ocom.common.enums.MasterSlaveEnum;
import com.ocom.common.enums.ResultEnum;
import com.ocom.common.request.human.FeatureRequest;
import com.ocom.common.request.human.GetPerFeatureRequest;
import com.ocom.common.request.human.GetPerFeatureResponse;
import com.ocom.common.request.human.UpdateFeatureRequest;
import com.ocom.common.resp.Result;
import com.ocom.common.utils.ResultUtil;
import com.ocom.common.utils.bdface.GsonUtils;
import com.ocom.common.utils.bdface.HttpUtil;
import com.ocom.common.vo.company.FeatureVersionVo;
import com.ocom.common.vo.company.GetFeatureVersionVo;
import com.ocom.common.vo.webapi.BDFaceFeature;
import com.ocom.human.dao.IDaoPersonnelFeature;
import com.ocom.human.feignclient.CompanyClientService;
import com.ocom.human.service.PersonnelFeatureService;
import com.ocom.mysql.aspect.DataSourceAspect;
import com.sun.org.apache.bcel.internal.generic.GOTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PersonnelFeatureServiceImpl extends ServiceImpl<IDaoPersonnelFeature, EntityPersonnelFeature> implements PersonnelFeatureService {

    @Autowired
    private IDaoPersonnelFeature dao;
    @Autowired
    private CompanyClientService companyClientService;

    private static final String CLIENT_ID = "ZfedCGbL7ZKR6ILKyOQGzOKF";
    private static final String CLIENT_SECRET = "LPj7mTe9vdEbqKdwagrI3EBVjGodFMw9";



    @Override
    @DataSourceAspect(type = DataSourceEnum.PART_DB, isMaster = MasterSlaveEnum.MASTER)
    public boolean updateFeature(Long companyId, UpdateFeatureRequest request) {
        QueryWrapper<EntityPersonnelFeature> queryWrapper = Wrappers.query();
        queryWrapper.eq("com_id", companyId);
        queryWrapper.eq("version", request.getVersion());
        queryWrapper.eq("p_id", request.getPId());
        queryWrapper.orderByDesc("update_time");
        queryWrapper.last("limit 1");
        EntityPersonnelFeature entityPersonnelFeature = this.getOne(queryWrapper);
        if (null == entityPersonnelFeature) {
            entityPersonnelFeature = new EntityPersonnelFeature();
            entityPersonnelFeature.setComId(companyId);
            entityPersonnelFeature.setPId(request.getPId());
            entityPersonnelFeature.setVersion(request.getVersion());
        }
        if (StringUtils.isNotBlank(request.getUrl())) {
            entityPersonnelFeature.setPPhotoUrl(request.getUrl());
            entityPersonnelFeature.setFeature(request.getFeature());
            entityPersonnelFeature.setProbability(request.getProbability());
        }
        if (StringUtils.isNotBlank(request.getUrl2())) {
            entityPersonnelFeature.setPPhotoUrl2(request.getUrl2());
            entityPersonnelFeature.setFeature2(request.getFeature2());
            entityPersonnelFeature.setProbability2(request.getProbability2());
        }

        return saveOrUpdate(entityPersonnelFeature);
    }

    public static void main(String[] args) {
    }

    @Override
    @DataSourceAspect(type = DataSourceEnum.PART_DB, isMaster = MasterSlaveEnum.SLAVE)
    public Map<String, Object> getPerFeature(Long companyId, GetPerFeatureRequest request) {
        Map<String, Object> map = new HashMap<>();
        PageHelper.startPage(request.getPage(), request.getSize());
        List<Integer> deptList = null;
        List<String> versionList = null;
        if (null != request.getDeptIds()) {
            deptList = Arrays.asList(request.getDeptIds());
        }
        if (null != request.getVersions()) {
            versionList = Arrays.asList(request.getVersions());
        }

        List<GetPerFeatureResponse> list = dao.getPerFeature(companyId, request.getPId(), deptList, request.getPName(), request.getPCode(), versionList, request.getProbabilityMin(), request.getProbabilityMax(), request.getStartTime(), request.getEndTime());
        PageInfo<GetPerFeatureResponse> listPageInfo = new PageInfo<>(list);
        map.put("total", listPageInfo.getTotal());
        map.put("list", list);
        return map;
    }

    @Override
    @DataSourceAspect(type = DataSourceEnum.PART_DB, isMaster = MasterSlaveEnum.MASTER)
    public Result feature(Long companyId, FeatureRequest request) {
        try {
            Result featureVersionResult = companyClientService.getFeatureVersion(companyId);
            if (200 != featureVersionResult.getCode() && null == featureVersionResult.getData()) {
                return ResultUtil.error(ResultEnum.Err_1001);
            }
            List<GetFeatureVersionVo> getFeatureVersionVos = JSON.parseArray(JSON.toJSONString(featureVersionResult.getData()), GetFeatureVersionVo.class);

            Map<String, String> versionMap = getFeatureVersionVos.stream().collect(Collectors.toMap(e -> e.getDockApiCode(), e -> e.getPagePara(), (e1, e2) -> e1));

            for (GetFeatureVersionVo featureVersionVo : getFeatureVersionVos) {

                //TODO 百度算法  临时区分，后续调整
                if ("baidu".equals(featureVersionVo.getInitApiPara())) {

                    String version = versionMap.get(request.getVersion());
                    if (StringUtils.isNotBlank(version)) {
                        executeUpdateFeature(companyId, request.getPId(), request.getUrl(), request.getUrl2(), request.getVersion(), version);
                    } else {
                        Iterator<Map.Entry<String, String>> iterator = versionMap.entrySet().iterator();
                        while (iterator.hasNext()) {
                            Map.Entry<String, String> next = iterator.next();
                            executeUpdateFeature(companyId, request.getPId(), request.getUrl(), request.getUrl2(), next.getKey(), next.getValue());
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("人脸特征值更新失败：{}", request);
        }

        return ResultUtil.success();
    }

    private boolean executeUpdateFeature(Long companyId, Long pId, String url, String url2, String versionKey, String version) throws InterruptedException {
        UpdateFeatureRequest updateFeatureRequest = new UpdateFeatureRequest();
        updateFeatureRequest.setVersion(versionKey);
        updateFeatureRequest.setComId(companyId);
        updateFeatureRequest.setPId(pId);

        boolean check = false;
        final int retryCount = 5;

        if (StringUtils.isNotBlank(url)) {
            for (int i = 0; i <= retryCount; i++) {
                BDFaceFeature faceFeature = faceFeature(url, version);
                if (null != faceFeature && 0 == faceFeature.getErrorCode() && 0 < faceFeature.getResult().getFaceList().size()) {
                    BDFaceFeature.FaceListVo faceListVo = faceFeature.getResult().getFaceList().get(0);
                    check = true;
                    updateFeatureRequest.setUrl(url);
                    updateFeatureRequest.setFeature(faceListVo.getFeature());
                    updateFeatureRequest.setProbability(faceListVo.getFaceProbability());
                    break;
                } else {
                    log.error("请求人脸特征值失败！【{}】，【{}】 开始重试！【{}】", pId, faceFeature, i);
                    Thread.sleep(500l);
                }
            }
        }

        if (StringUtils.isNotBlank(url2)) {
            for (int i = 0; i <= retryCount; i++) {
                BDFaceFeature faceFeature2 = faceFeature(url2, version);
                if (null != faceFeature2 && 0 == faceFeature2.getErrorCode() && 0 < faceFeature2.getResult().getFaceList().size()) {
                    BDFaceFeature.FaceListVo faceListVo = faceFeature2.getResult().getFaceList().get(0);
                    check = true;
                    updateFeatureRequest.setUrl2(url2);
                    updateFeatureRequest.setFeature2(faceListVo.getFeature());
                    updateFeatureRequest.setProbability2(faceListVo.getFaceProbability());
                    break;
                } else {
                    log.error("请求人脸特征值2失败！【{}】，【{}】 开始重试！【{}】", pId, faceFeature2, i);
                    Thread.sleep(500l);
                }
            }
        }
        if (check) {
            check = updateFeature(companyId, updateFeatureRequest);
        }
        return check;
    }


    private BDFaceFeature faceFeature(String faceUrl, String version) {
        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/face/v1/feature";
        try {
            Map<String, Object> map = new HashMap<>();
            map.put("image", faceUrl);
            map.put("image_type", "URL");
            map.put("version", version);

            String param = GsonUtils.toJson(map);

            // 注意这里仅为了简化编码每一次请求都去获取access_token，线上环境access_token有过期时间， 客户端可自行缓存，过期后重新获取。
            String accessToken = getAuth(CLIENT_ID, CLIENT_SECRET);

            String result = HttpUtil.post(url, accessToken, "application/json", param);

            BDFaceFeature bdFaceFeature = JSON.parseObject(result, BDFaceFeature.class);

            log.info("faceDetect result:[{}]", bdFaceFeature.getErrorMsg());

            return bdFaceFeature;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getAuth(String ak, String sk) {
        // 获取token地址
        String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
        String getAccessTokenUrl = authHost
                // 1. grant_type为固定参数
                + "grant_type=client_credentials"
                // 2. 官网获取的 API Key
                + "&client_id=" + ak
                // 3. 官网获取的 Secret Key
                + "&client_secret=" + sk;
        try {
            URL realUrl = new URL(getAccessTokenUrl);
            // 打开和URL之间的连接
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();

            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String result = "";
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }

            JSONObject jsonObject = JSON.parseObject(result);
            String access_token = jsonObject.getString("access_token");
            return access_token;
        } catch (Exception e) {
            log.error("获取token失败！");
            e.printStackTrace();
        }
        return null;
    }

}
